package com.nononsenseapps.feeder.ui.feed

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Rect
import android.net.Uri
import android.os.*
import android.view.*
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.text.htmlEncode
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
import androidx.lifecycle.Observer
import androidx.paging.LoadState
import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.DiffUtil.ItemCallback
import com.gitee.wsl.struct.category.CategoryItemWarp
import cn.ekuma.odbo.mobile.category.ui.OnTreeNodeListenerAdapter
import com.gitee.wsl.android.common.ui.activity.createFile
import com.gitee.wsl.android.common.ui.activity.filePicker
import com.gitee.wsl.android.common.ui.activity.folderPicker
import com.gitee.wsl.android.common.ui.activity.requestMultiplePermission
import com.gitee.wsl.android.common.ui.activity.requestPermission
import com.gitee.wsl.android.common.ui.activity.startActivity
import com.gitee.wsl.common.ui.ext.firstVisibleItemPosition
import com.gitee.wsl.common.ui.ext.lastVisibleItemPosition
import com.gitee.wsl.common.ui.ext.startActivity
import com.gitee.wsl.common.ui.ext.toast
import com.gitee.wsl.common.ui.ext.toastError
import com.gitee.wsl.common.ui.ext.toastSuccess
import com.gitee.wsl.store.StateSavedVar
import com.gitee.wsl.jvm.store.mmkv.MMKVStoreServer
import com.github.tutorialsandroid.appxupdater.AppUpdaterUtils
import com.github.tutorialsandroid.appxupdater.enums.AppUpdaterError
import com.github.tutorialsandroid.appxupdater.enums.UpdateFrom
import com.github.tutorialsandroid.appxupdater.objects.Update
import com.google.android.material.tabs.TabLayout
import com.haibin.calendarview.CalendarLayout
import com.haibin.calendarview.CalendarView
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.huawei.hms.hmsscankit.ScanKitActivity
import com.huawei.hms.hmsscankit.ScanUtil
import com.huawei.hms.ml.scan.HmsScan
import com.kongzue.stacklabelview.StackLabel
import com.lxj.xpopup.XPopup
import com.lxj.xpopup.core.AttachPopupView
import com.lxj.xpopup.core.BasePopupView
import com.lxj.xpopup.core.CenterPopupView
import com.nononsenseapps.feeder.cache.LocalFileCacheManager
import com.nononsenseapps.feeder.db.ARG
import com.nononsenseapps.feeder.db.SYSTEM_FEED_LIST
import com.nononsenseapps.feeder.db.entity.Feed
import com.nononsenseapps.feeder.db.entity.FeedItemFeature
import com.nononsenseapps.feeder.db.entity.RuleFactory
import com.nononsenseapps.feeder.db.room.*
import com.nononsenseapps.feeder.db.view.PreviewItem
import com.nononsenseapps.feeder.model.*
import com.nononsenseapps.feeder.model.category.FeedItemCategoryHelper
import com.nononsenseapps.feeder.model.opml.exportOpml
import com.nononsenseapps.feeder.model.opml.importOpml
import com.nononsenseapps.feeder.net.RssServer
import com.nononsenseapps.feeder.net.RssServer.isRssServerRunning
import com.nononsenseapps.feeder.net.RssServer.start
import com.nononsenseapps.feeder.net.RssServer.stop
import com.nononsenseapps.feeder.processor.RuleManager
import com.nononsenseapps.feeder.sync.local.source.dir.DirSource
import com.nononsenseapps.feeder.sync.local.source.email.EmailSource_K9
import com.nononsenseapps.feeder.sync.local.source.sms.SmsSource
import com.nononsenseapps.feeder.ui.*
import com.nononsenseapps.feeder.ui.base.*
import com.nononsenseapps.feeder.ui.category.CompAdapter
import com.nononsenseapps.feeder.ui.category.FeedItemTagTreeAdapter
import com.nononsenseapps.feeder.ui.common.DividerColor
import com.nononsenseapps.feeder.ui.reader.sample.openEnclosure
import com.nononsenseapps.feeder.ui.reader.sample.showImagePreview
import com.nononsenseapps.feeder.ui.rule.FeedRuleListActivity
import com.nononsenseapps.feeder.ui.tag.*
import com.nononsenseapps.feeder.util.*
import com.nononsenseapps.feeder.util.NotificationUtil.cancelNotification
import com.nononsenseapps.feeder.worker.requestFeedSync
import fr.gaulupeau.apps.Poche.tts.TtsConverter
import fr.gaulupeau.apps.Poche.tts.bean.Article
import fr.gaulupeau.apps.Poche.tts.item.TextItem
import fr.gaulupeau.apps.Poche.tts.source.StringArrayTextInterface
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import me.dkzwm.widget.srl.SmoothRefreshLayout
import timber.log.Timber
import top.amot.forceview.ForceView
import top.amot.forceview.Simulation
import top.amot.forceview.layout.DefaultLayout
import top.amot.forceview.model.Link
import top.amot.forceview.model.Node
import top.amot.forceview.model.NodeModel
import java.lang.Runnable
import java.net.URL
import java.util.*

@InternalCoroutinesApi
abstract class AbstractFeedFragment : CoroutineScopedFragment() {

    protected lateinit var recyclerView: RecyclerView
    protected lateinit var swipeRefreshLayout: SmoothRefreshLayout
    protected lateinit var emptyView: View
    protected lateinit var emptyAddFeed: View
    protected lateinit var emptyOpenFeeds: View
    protected lateinit var stackLabelView:StackLabel
    protected lateinit var classicHeader: FeedHeader
    protected lateinit var tabLayout: TabLayout

    protected lateinit var forceView: ForceView

    /*protected val feedViewModel by lazy { getFeedViewModel() }
    val feedItemsViewModel by lazy { getFeedItemsViewModel() }

    protected val feedListViewModel by lazy{ getFeedListViewModel() }*/

    protected val feedViewModel by viewModels<FeedViewModel>()
    val feedItemsViewModel by viewModels<FeedItemsViewModel>()

    protected val feedListViewModel by activityViewModels<FeedListViewModel>()
    protected val feedId: Long
            get() = feedItemsViewModel.feedId

    protected val feedTag: String
            get() = feedItemsViewModel.feedGroup

    protected var isBackgroundEmptyViewChange = false

    protected lateinit var quickFeedUnreadCountList: List<FeedUnreadCount>

    protected val handler = Handler(Looper.getMainLooper())

    protected var toggleEmptyViewRun:Runnable? = null

    protected var currentListJob:Job?=null

    protected lateinit var itemPageListAdapter: FeedItemPagedListAdapter

    protected lateinit var itemTreeAdapter : FeedItemTagTreeAdapter

   protected val adapter= CompAdapter()

    init {
        // Listens on sync state changes
        lifecycleScope.launchWhenResumed {
            EventBusUtils.addSyncStateChangeListener(this@AbstractFeedFragment) { state ->
                Timber.d("linter for fire sync state change")
                when {
                    state.id == feedId -> onSyncBroadcast(false)
                    state.tag.isNotEmpty() && state.tag == feedTag -> onSyncBroadcast(false)
                }
                when (state.success) {
                    true -> state.description.isNotBlank()
                        .isTrue { requireContext().toastSuccess(state.description) }
                    false -> requireContext().toastError(state.description)
                }
            }

        }
    }

    fun currentListReadRefreshCheck(){
        val refreshAble = feedItemsViewModel.isReadBackRefreshAble
        Timber.d("read refresh check refreshAble:$refreshAble , startReadTime:${feedItemsViewModel.startReadTime}....")
        if(refreshAble) {
            refreshCurrentList()
            recyclerView.scrollToPosition(0)
        }
    }

    fun refreshCurrentList(lastDay: Date=Calendar.getInstance().time,init:Boolean=false){
        currentListJob?.cancel()
        currentListJob = lifecycleScope.launch {
             repeatOnLifecycle(state = Lifecycle.State.STARTED) {
                feedItemsViewModel.startReadTime = lastDay
                feedItemsViewModel.getCurrentPagingDataFlow().collect {
                    adapter.submitData(it)
                }
            }
        }
        if(!init && feedItemsViewModel.mustScrollToTop){
            Timber.d("read mustScrollToTop ..")
            feedItemsViewModel.readTypeChanged = false
            recyclerView.scrollToPosition(0)
        }
    }    

    private lateinit var requestReadEmail:ActivityResultLauncher<String>

    //private lateinit var requestReadDir:ActivityResultLauncher<Uri?>

    protected var simulation: Simulation?=null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var feedId = ID_UNSET
        var feedGroup:String ?= null
        arguments?.let { arguments ->
            //url = arguments.getString(ARG.LINK)
            feedId = arguments.getLong(ARG.FEED_ID, ID_UNSET)
            feedGroup = arguments.getString(ARG.TAG)

            arguments.getLongArray(EXTRA_FEEDITEMS_TO_MARK_AS_NOTIFIED)?.let {
                feedItemsViewModel.markFeedItemAsNotified(it.toList())
            }

            // Set this to equal title in case it's not a feed
        }

        setHasOptionsMenu(true)

        feedItemsViewModel.initArguments(feedId,feedGroup)

        refreshCurrentList(lastDay=feedItemsViewModel.startReadTime,init = true)

        requestReadEmail=registerForActivityResult(ActivityResultContracts.RequestPermission()){
            Timber.d("k9 email read able:$it")
        }

       /* requestReadDir = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()){
            Timber.d(" read dir:$it")

            it?:return@registerForActivityResult

            lifecycleScope.launch(Dispatchers.IO) {

                val url=DirSource.buildUrl(it.toString().htmlEncode())

                if (feedDao.isExitsFeed(url)) {
                    withContext(Dispatchers.Main) {
                        requireContext().makeToast("订阅已存在")
                    }
                } else {
                    val feed = Feed(
                        url = URL(url),
                        title = it.path.toString(),
                        tag = requireContext().getString(R.string.feed_type_dir)
                    )

                    feedDao.upsert(feed)

                    withContext(Dispatchers.Main) {
                        editFeed(feed.id, feed.title, feed.tag, _feed = feed)
                    }
                }
            }
        }*/
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val rootView = inflater.inflate(R.layout.fragment_feed, container, false)
        recyclerView = rootView.findViewById(android.R.id.list)

        // improve performance if you know that changes in content
        // do not change the size of the RecyclerView
        recyclerView.setHasFixedSize(true)

        //initLayoutManager()

        // Setup swipe refresh
        classicHeader = FeedHeader(context)
        swipeRefreshLayout = rootView.findViewById(R.id.swipe_refresh)
        swipeRefreshLayout.apply{
            setHeaderView(classicHeader)

            setEnablePullToRefresh(true)
            setEnableKeepRefreshView(true)
            setDisableLoadMoreWhenContentNotFull(true)

            setOnRefreshListener(object: SmoothRefreshLayout.OnRefreshListener{
                override fun onLoadingMore() {
                }
                override fun onRefreshing() {
                    Timber.d("on Refreshing...")
                    feedItemRefreshing()
                }
            })
        }


        // Set up the empty view
        emptyView = rootView.findViewById(android.R.id.empty)
        emptyAddFeed = emptyView.findViewById(R.id.empty_add_feed)
        @Suppress("DEPRECATION")
        (emptyAddFeed as TextView).text = android.text.Html.fromHtml(getString(R.string.empty_feed_add))
        emptyOpenFeeds = emptyView.findViewById(R.id.empty_open_feeds)
        @Suppress("DEPRECATION")
        (emptyOpenFeeds as TextView).text = android.text.Html.fromHtml(getString(R.string.empty_feed_open))

        stackLabelView=emptyView.findViewById(R.id.stackLabelView)

        forceView = emptyView.findViewById(R.id.forceView)

        forceView.setOnNodeClickListener{
            requireContext().toast(it.toString())
        }

        emptyAddFeed.setOnClickListener {
            startActivity(Intent(activity,EditFeedActivity::class.java))
        }

        emptyOpenFeeds.setOnClickListener {
            openFeedsList()
        }

        stackLabelView.setOnLabelClickListener { index, v, s -> changeFeedById(quickFeedUnreadCountList[index].id,s) }

        stackLabelView.setOnLabelLongClickListener{ index, _, _->
            changeFeedAttentionLevel(quickFeedUnreadCountList[index])
        }

        // specify an adapter
        itemPageListAdapter = FeedItemPagedListAdapter(requireActivity(),itemDao=feedItemDao, actionCallback = object : ActionCallback {

            override fun onEnclosureLinkClick(item: PreviewItem) {
                openEnclosure(item.enclosureLink!!,item.plainTitle,item.feedTitle,item.imageUrl)
            }

            override fun onItemDelete(item: PreviewItem) {
                lifecycleScope.launch(Dispatchers.IO){
                    if(item.feedId== RECYCLE_FEED_ID)
                       feedItemDao.deleteFeedItem(item.id)
                    else
                       feedItemDao.moveItemToFeed(item.id, RECYCLE_FEED_ID)
                }
            }

            override fun onAuthorItemClick(item: PreviewItem) {
                item.feedId?.let {
                    changeFeedById(it,item.feedTitle)
                }
            }

            override fun onItemClick(item: PreviewItem) {
                globalViewModel.changeCurrentItem(item)
            }

            override fun coroutineScope(): CoroutineScope {
                return lifecycleScope
            }

            override fun onDismiss(item: PreviewItem?) {
                item?.let {
                    if(it.unread)
                        globalViewModel.lastUndoReadItemID=it.id
                    feedItemsViewModel.toggleReadState(it)
                }
            }

            override fun onSwipeStarted() {
                // SwipeRefreshLayout does not honor requestDisallowInterceptTouchEvent
                swipeRefreshLayout.isEnabled = false
            }

            override fun onSwipeCancelled() {
                // SwipeRefreshLayout does not honor requestDisallowInterceptTouchEvent
                swipeRefreshLayout.isEnabled = true
            }

            override fun markItemFeature(item: PreviewItem) {
                lifecycleScope.launch(Dispatchers.IO) {
                    val listStringArray = mutableListOf<FeedItemFeature>()
                    listStringArray.add(FeedItemFeature(title = getString(R.string.no_feature)))
                    var selectIndex = 0
                    globalViewModel.feedItemFeatureList().let{
                        listStringArray.addAll(it)
                        listStringArray.forEachIndexed { index, feature ->
                            if (item.feature == feature.id)
                                selectIndex = index
                        }
                        showFeatureSelect(selectIndex, listStringArray) { featureId, _ ->
                            lifecycleScope.launch(Dispatchers.IO) {
                                if(featureId == ID_UNSET){
                                    feedItemDao.setFeedItemFeature(id = item.id, featureId = null)
                                }else {
                                    /*if (item.feedId != FAVORITE_FEED_ID)
                                        feedItemDao.markAsFavorite(id = item.id, tag = item.itemTags)*/
                                    feedItemDao.setFeedItemFeature(id = item.id, featureId = featureId)
                                }
                            }
                        }
                    }
                }
            }

            override fun showCurrentFeature(item: PreviewItem) {
                item.feature?.let{
                    lifecycleScope.launch(Dispatchers.IO) {
                        feedItemFeatureDao.get(it).let{feature->
                            withContext(Dispatchers.Main){
                                feedItemsViewModel.filterWithFeed(feature.id,feature.title)
                                refreshCurrentList()
                            }
                        }
                    }
                }
            }

            override fun removeItemFeature(item: PreviewItem) {
                item.feature?.let {
                    lifecycleScope.launch(Dispatchers.IO) {
                        feedItemDao.setFeedItemFeature(id = item.id, featureId = null)
                    }
                }
            }

            override fun showImagePreview(currentPosition: Int, urls: List<String>, srcView: ImageView?) {
                showImagePreview(activity!!,currentPosition,urls,srcView)
            }

            override fun onItemTagsEdit(item: PreviewItem) {
                val itemTags= mutableListOf<String>()
                itemTags.addAll(NlpUtils.buildTags(item.plainTitle))
                //itemTags.addAll(getItemTags())
                popItemTagsEdit(item.id,item.itemTags.split(","),itemTags){_,tagStr->
                    item.itemTags=tagStr.joinToString(",")
                }
            }

            override fun markAsFavorite(item: PreviewItem) {
                item.feedId?.let{
                    feedItemsViewModel.markFeedItemAsFavorite(item.id,tag = item.tag)
                    requireContext().makeToast(getString(R.string.feed_favorite_success))
                }
            }

            override fun downLoadEnclosure(item: PreviewItem) {
                item.enclosureLink?.let { downLoadEnclosure(item.id, it) }
            }

            override fun pauseDownLoadEnclosure(item: PreviewItem) {
                item.enclosureLink?.let { pauseDownLoadEnclosure(item.id, it) }
            }

            override fun resumeDownLoadEnclosure(item: PreviewItem) {
                item.enclosureLink?.let { resumeDownLoadEnclosure(item.id, it) }
            }

            override fun cancelDownLoadEnclosure(item: PreviewItem) {
                item.enclosureLink?.let {
                    cancelDownLoadEnclosure(item.id,it)
                }
            }

            override fun delDownLoadEnclosure(item: PreviewItem) {
                item.enclosureLink?.let {
                    delDownLoadEnclosure(item.id,it)
                }
            }

            override fun preLoadState(item: PreviewItem): Int {
                return LocalFileCacheManager.getDownLoadState(requireContext(),item.enclosureLink!!)
            }

            override fun moveItemToFeed(item: PreviewItem, feedId: Long) {
                item.feedId?.let{
                    lifecycleScope.launch(Dispatchers.IO) {
                        feedItemDao.moveItemToFeed(item.id, toFeedId = feedId)
                    }
                }
            }

            override fun markAsReadHistory(item: PreviewItem) {
                lifecycleScope.launch(Dispatchers.IO) {
                    if(item.unread)  feedItemDao.markAsRead(item.id)
                    feedItemDao.markAsReadHistory(item.id)
                }
            }

            override fun navToReaderWebViewFragment(link: String?, enclosureLink: String?) {
               navigateToReaderWebViewFragment(link,enclosureLink)
            }

            override fun navToReaderFragment() {
                globalViewModel.changeCurrentItemList(adapter.getCurrentItemList())
                navigateToReaderFragment()
            }

            override fun authorVisible(): Boolean {
                return feedItemsViewModel.currentModel != ItemListViewModel.FEED
            }

            override fun markAboveAllRead(item: PreviewItem) {
                adapter.getAboveItemList(item)?.let{
                    markCurrentListAsRead(it)
                    if(feedItemsViewModel.isOnlyUnread())
                        recyclerView.scrollToPosition(0)
                }
            }


            override fun makeAllRead() {
                markCurrentListAsReadAndSync(adapter.getCurrentItemList())
            }

            override fun generateQRCode(item: PreviewItem) {
                item.link?.let {
                    generateQRCode(it,item.plainTitle)
                }
            }

            override fun generateEnclosureQRCode(item: PreviewItem) {
                item.enclosureLink?.let {
                    generateQRCode(it,item.enclosureFilename)
                }
            }

            override fun markAddFeedRule(item: PreviewItem, adBlock: Boolean, adImage: Boolean, custom: Boolean) {
                if(custom) {
                    navigateToFeedRuleFragment(item.feedId, item.plainTitle,adFlag = adBlock)
                }else {
                    val feedRule = if(adImage)
                            RuleFactory.adImageRule("image:${item.imageUrl}",item.imageUrl ?: "",item.feedId)
                        else
                            RuleFactory.adTitleRule(item.plainTitle,item.plainTitle,item.feedId,RECYCLE_FEED_ID)
                    globalViewModel.installFeedRule(feedRule)
                    RuleManager.INSTANCE?.feedRuleChanged(item.feedId?: ID_ALL_FEEDS)
                    Toast.makeText(context, "规则保存${feedRule.title}/t", Toast.LENGTH_SHORT).show()
                }
            }

            override fun markItemAttentionLevel(item: PreviewItem, attentionLevel: Int) {
                feedItemsViewModel.markFeedItemAttentionLevel(item.id,attentionLevel)
            }

            override fun speakFromCurrent(item: PreviewItem) {
                val textInterface=StringArrayTextInterface(TtsConverter(requireContext()),
                    Article(
                        feedId.toInt(),
                        null,
                        feedItemsViewModel.displayTitle.value,
                        feedTag,
                        null
                    )
                )
                adapter.getBelowItemList(item)?.forEachIndexed{ index,previewItem ->
                    if( (index+1) % 20 == 0)
                         textInterface.addItem(TextItem(" 当前播放到...第 ${index+1} 条 ...", 0F, 0F, null))
                     textInterface.addItem(TextItem(previewItem.plainTitle+"... , ... , ... \n ...,\n", 0F, 0F, null))

                    }
                textInterface.restoreFromStart()
                ttsSpeak(textInterface)
            }
        })

        adapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

        itemTreeAdapter = FeedItemTagTreeAdapter(globalViewModel,feedItemsViewModel,object: OnTreeNodeListenerAdapter() {

            override fun onClick(
                node: CategoryItemWarp,
                holder: RecyclerView.ViewHolder
            ): Boolean {
                val item=node.data
                if(item is PreviewItem){
                    globalViewModel.changeCurrentItem(item)
                    navigateToReaderFragment()
                }
                return false
            }

            override fun onToggle(isExpand: Boolean, holder: RecyclerView.ViewHolder) {
                TODO("Not yet implemented")
            }

        })

        adapter.put(CompAdapter.ADAPTER_TYPE_TREE,this.itemTreeAdapter)
        adapter.put(CompAdapter.ADAPTER_TYPE_LIST,this.itemPageListAdapter,true)

        recyclerView.adapter = adapter

        initLayoutManager()

        adapter.addLoadStateListener {
            //Timber.d("adapter.addLoadStateListener state:$it,itemCount:${adapter.itemCount}")
            val itemCount = adapter.itemCount
            if(it.refresh is LoadState.NotLoading){
                Timber.d("observer feed item list change,isBackgroundEmptyViewChange:$isBackgroundEmptyViewChange\t itemCount:$itemCount")
                if(it.append is LoadState.NotLoading && it.append.endOfPaginationReached && itemCount == 0){
                    toggleEmptyViewDelay(show = true)
                }else if( adapter.itemCount > 0) {
                    removeToggleEmptyViewDelayRun()
                    if (!isBackgroundEmptyViewChange) {
                        toggleEmptyView(false)
                        if(itemCount < 5 )
                            EventBusUtils.fireCurrentlyFabShow(true)
                    }
                }
            }
        }

        recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                if( dy<0 && recyclerView.firstVisibleItemPosition == 0 && feedItemsViewModel.blackSynced) {
                    Timber.d("on scroll top....")
                    feedItemsViewModel.blackSynced = false
                    currentListReadRefreshCheck()
                    return
                }
                if(globalViewModel.reverseListOrder.value==true&&feedItemsViewModel.isSyncAble()&&dy>0&&recyclerView.lastVisibleItemPosition==adapter.itemCount-7&&!swipeRefreshLayout.isRefreshing&&!feedItemsViewModel.loadingMore) {
                     Timber.d("on loading more....")
                     feedItemsViewModel.loadingMore()
                     feedItemRefreshing()
                }
            }
        })


        tabLayout=rootView.findViewById(R.id.tabLayout)

        tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
            override fun onTabReselected(tab: TabLayout.Tab?) {
                Timber.d("tab onTabReselected:%s", tab?.text)
                tab?.tag?.let {item ->  changeFeedById((item as Feed).id,item.title) }
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {
                Timber.d("tab onTabUnselected:%s", tab?.text)
            }

            override fun onTabSelected(tab: TabLayout.Tab?) {
                Timber.d("tab  selected:%s", tab?.text)
                tab?.tag?.let {item-> changeFeedById((item as Feed).id,item.title) }
            }
        })

        bindViewModel()

        //updateForceView()

        return rootView
    }


    /*protected fun saveCurrentPosition(){
        val firstPosition = recyclerView.firstVisibleItemPosition
        feedItemsViewModel.lastViewFeedItemId = if(firstPosition>=1) adapter.getFeedItem(firstPosition-1)!!.id else 0
        Timber.d("onStop save feedItemsViewModel.lastViewFeedItemId:${feedItemsViewModel.lastViewFeedItemId} ,firstPosition:$firstPosition")
    }*/

    protected fun recoverCurrentPosition(){
        if(feedItemsViewModel.lastViewFeedItemId > 0){
            var lastViewPosition = -1
            adapter.getCurrentItemList().forEachIndexed { index, previewItem ->
                if(previewItem.id == feedItemsViewModel.lastViewFeedItemId){
                    lastViewPosition = index
                    return@forEachIndexed
                }
            }
            if(lastViewPosition>=0)
                recyclerView.scrollToPosition(lastViewPosition + 1)
            Timber.d("feedItemsViewModel.lastViewFeedItemId:${feedItemsViewModel.lastViewFeedItemId},lastViewPosition:$lastViewPosition")
        }
    }

    protected fun changeAdapter(treeNodeName:String="list"){
        initLayoutManager()
    }

    open fun initLayoutManager(){
        changeToLinearLayoutManager()
    }

    fun toggleEmptyViewDelay(show:Boolean){
       removeToggleEmptyViewDelayRun()
       toggleEmptyViewRun = Runnable{
            toggleEmptyView(show)
        }
        handler.postDelayed(toggleEmptyViewRun!!,1000)
    }

    fun removeToggleEmptyViewDelayRun(){
        toggleEmptyViewRun?.let {
            handler.removeCallbacks(it)
            toggleEmptyViewRun=null
        }
    }

    fun toggleEmptyViewBackground(){
        removeToggleEmptyViewDelayRun()
        val emptyViewShowing = emptyView.visibility == View.VISIBLE
        toggleEmptyView(!emptyViewShowing)
        isBackgroundEmptyViewChange=!isBackgroundEmptyViewChange
    }

    fun toggleEmptyView(show:Boolean){
        if((show && emptyView.visibility == View.VISIBLE)||(!show && emptyView.visibility == View.GONE)) return
        if(show) {
            swipeRefreshLayout.visibility=View.GONE
            emptyView.visibility = View.VISIBLE
            updateQuickFeedUnreadList()
            //if(simulation==null)
               updateForceView()
            /*else
               simulation?.restart()*/
        } else {
            swipeRefreshLayout.visibility = View.VISIBLE
            emptyView.visibility = View.GONE
            /*simulation?.stop()
            simulation = null*/
        }
        
        EventBusUtils.fireCurrentlyFabShow(true)
    }


     fun changeToLinearLayoutManager(){
        resertLayoutManager()
        val layoutManager = LinearLayoutManager(activity)
         recyclerView.addItemDecoration(object: RecyclerView.ItemDecoration() {
             override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                 outRect.top =  5
                 outRect.bottom = 40
             }
         })
        recyclerView.addItemDecoration(DividerColor(activity,  DividerColor.VERTICAL_LIST))
        recyclerView.layoutManager=layoutManager
    }

    private fun resertLayoutManager(){
        recyclerView.itemDecorationCount.let {
            for (index in it-1 downTo 0)
                recyclerView.removeItemDecorationAt(index)
        }
    }

     fun changeToStaggeredGridLayoutManager(layoutStyle:Int= StaggeredGridLayoutManager.VERTICAL,largeScreen:Boolean=false){
        resertLayoutManager()
        val cols = TabletUtils.numberOfFeedColumns(activity)
        // use a grid layout
        val layoutManager = StaggeredGridLayoutManager(cols,layoutStyle)
        recyclerView.addItemDecoration(object: RecyclerView.ItemDecoration() {
            override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
                //获取当前item的下标
                //val pos = parent.getChildLayoutPosition(view)
                val pos = (view.layoutParams as StaggeredGridLayoutManager.LayoutParams).spanIndex
                if (pos < cols) {
                    outRect.top = 0
                } else {
                    outRect.top = if(largeScreen) 20 else 10
                }
                outRect.left = 5
                outRect.right = 5
                if(largeScreen)
                    outRect.bottom=30
            }
        })

        recyclerView.addItemDecoration( DividerColor(activity,  DividerColor.HORIZONTAL_LIST))
        recyclerView.layoutManager=layoutManager
    }

    abstract fun openFeedsList()

    protected fun feedItemRefreshing() {
        if(feedId > ID_UNSET) {
            feedViewModel.loadFeed(feedId).let{
                classicHeader.setRefreshingStr(getString(R.string.sr_last_update)+DateUtils.timeAlong(it.lastSync.toDate()))
            }
        }else
            classicHeader.setRefreshingStr(feedTag)
        requestFeedSyncRead(true)
    }

    protected fun changeFeedById(it:Long,title: String){
        if(it != ID_UNSET  && feedId != it) {
            isBackgroundEmptyViewChange=false
            if(it == ID_ALL_FEEDS)
                feedItemsViewModel.filterWithAllFeed()
            else
                 feedItemsViewModel.filterWithFeed(it,title)
            refreshCurrentList()
        }

    }

    protected fun changeFeedAttentionLevel(feed:FeedUnreadCount){
        changeAttentionLevel(feed.attentionLevel){
            feedViewModel.changeFeedAttentionLevel(feed.id,it)
        }
    }


    @SuppressLint("NotifyDataSetChanged")
    protected fun bindViewModel(){
        globalViewModel.hotFeedList.observe(viewLifecycleOwner,Observer {
            if(it.isNullOrEmpty()){
                tabLayout.visibility = View.GONE
            }else {
                tabLayout.visibility = View.VISIBLE
                lifecycleScope.launch(Dispatchers.IO){
                    feedListViewModel.getLiveHotFeeds(it).let {
                        withContext(Dispatchers.Main) {
                            it.forEach { item -> tabLayout.addTab(tabLayout.newTab().setTag(item).setText(item.displayTitle), false) }
                        }
                    }
                }
            }
        })

        feedItemsViewModel.feedViewListType.observe(viewLifecycleOwner, Observer {
            if(it != FeedViewListType.TREE)
                adapter.setFeedViewListType(it,null)
            else{
                val treeName=feedViewModel.getFeedLastOpenTreeName(feedId)
                adapter.setFeedViewListType(it,treeName)
            }
            adapter.notifyDataSetChanged()
        })

        globalViewModel.reverseListOrder.observe(viewLifecycleOwner, Observer {
            adapter.setReverseListOrder(it)
            adapter.notifyDataSetChanged()
        })

        feedItemsViewModel.displayTitle.observe(viewLifecycleOwner, Observer {
            changeAppTitle(it)
        })

        feedItemsViewModel.refreshAble.observe(viewLifecycleOwner, Observer {
            swipeRefreshLayout.setDisableRefresh(!it)
        })

    }

    open fun changeAppTitle(title: String){
        (activity as AppCompatActivity?)?.supportActionBar?.title = title
    }

    abstract fun getActivityIntent():Intent


    fun updateForceView(){
        lifecycleScope.launch(Dispatchers.IO){
            globalViewModel.loadHotItemTags().collect{ tagList ->
                val nodeModel=NodeModel()
                tagList.forEach {tag->
                    var level=0
                    tag.parentTag.let {
                        level=1
                    }
                    nodeModel.addNode(Node(tag.name,level))
                }
                createTestNodeTrue(nodeModel)
                simulation = Simulation.Builder().initDefault(requireContext()).nodeModel(nodeModel).initialLayout(DefaultLayout(requireContext())).build()
                withContext(Dispatchers.Main){
                    forceView.setSimulation(simulation!!)
                }
            }
        }
    }

    fun createTestNodeTrue(nodeModel:NodeModel){
        val nodes= ArrayList<Node>()
        val links= ArrayList<Link>()

        nodes.add(Node("A", 0)) // 0
        nodes.add(Node("B", 1)) // 1
        nodes.add(Node("C", 1)) // 2
        nodes.add(Node("D", 1)) // 3
        nodes.add(Node("E", 1)) // 4
        nodes.add(Node("F", 2)) // 5
        nodes.add(Node("G", 2)) // 6
        nodes.add(Node("H", 2)) // 7
        nodes.add(Node("I", 2)) // 8
        nodes.add(Node("J", 2)) // 9

        links.add(Link(nodes.get(0), nodes.get(1), "A-B"))
        links.add(Link(nodes.get(0), nodes.get(2), "A-C"))
        links.add(Link(nodes.get(0), nodes.get(3), "A-D"))
        links.add(Link(nodes.get(0), nodes.get(4), "A-E"))
        links.add(Link(nodes.get(1), nodes.get(5), "B-F"))
        links.add(Link(nodes.get(2), nodes.get(6), "C-G"))
        links.add(Link(nodes.get(3), nodes.get(7), "D-H"))
        links.add(Link(nodes.get(4), nodes.get(8), "E-I"))
        links.add(Link(nodes.get(4), nodes.get(9), "E-J"))

        val r = Random()
        for (i in 5..9) {
            val node: Node = nodes[i]
            val n = r.nextInt(10) + 10
            for (j in 0 until n) {
                val child = Node(node.text + (j + 1), 3)
                nodes.add(child)
                links.add(Link(node, child, node.text + "-" + child.text))
            }
        }

        val last: Int = nodes.size - 1

        for (i in last downTo last - 10 + 1) {
            val node: Node = nodes[r.nextInt(nodes.size)]
            val n = r.nextInt(10)
            for (j in 0 until n) {
                val child = Node(node.text + (j + 1), node.level + 1)
                nodes.add(child)
                links.add(Link(node, child, node.text + "-" + child.text))
            }
        }

        nodeModel.addNodes(nodes)
        nodeModel.addLinks(links)

        Timber.d("nodes count: " + nodes.size.toString() + ", links count:" + links.size)
    }

    protected fun updateQuickFeedUnreadList(){
        lifecycleScope.launch(Dispatchers.IO){
            feedListViewModel.getLiveFeedsWithUnreadCounts().map { items->
                if(feedItemsViewModel.currentModel == ItemListViewModel.FEED)
                    quickFeedUnreadCountList = items.filter { feedUnreadCount -> feedUnreadCount.id != feedId }
                else
                    quickFeedUnreadCountList = items
                quickFeedUnreadCountList.map { feedUnreadCount -> feedUnreadCount.title+'['+feedUnreadCount.unreadCount+']' }
            }.collect{
                withContext(Dispatchers.Main){
                    stackLabelView.setLabels(it)
                }
            }
        }
    }

    protected var featurePop:BasePopupView?=null

    protected suspend fun showFeatureSelect(selectIndex:Int=-1, featureList:List<FeedItemFeature>, selectFun:(Long?, String)->Unit)=withContext(Dispatchers.Main){
        featurePop = XPopup.Builder(context).asCustom(FeatureSelectCenterPopup(
            requireContext(), featureList = featureList, selectIndex = selectIndex,
            listener = object : FeatureCallBack {
                override fun featureSelect(feature: FeedItemFeature) {
                    selectFun.invoke(feature.id, feature.title)
                    dismissFeatureSelect()
                }

                override fun featureEdit(feature: FeedItemFeature, editCallBack: (String) -> Unit) {
                    XPopup.Builder(context)
                        .asInputConfirm(getString(R.string.feature), feature.title) { text ->
                            feature.title = text
                            lifecycleScope.launch(Dispatchers.IO) {
                                feedItemFeatureDao.update(feature)
                            }
                            editCallBack.invoke(text)
                        }.show()
                }

                override fun featureDel(feature: FeedItemFeature) {
                    lifecycleScope.launch(Dispatchers.IO) {
                        feedItemFeatureDao.delete(feature)
                    }
                }

                override fun featureAdd(featureId: FeedItemFeature) {
                    lifecycleScope.launch(Dispatchers.IO) {
                        feedItemFeatureDao.upsert(featureId)
                    }
                }
            },
        )).show()
    }

    protected fun dismissFeatureSelect(){
        featurePop?.dismiss()
        featurePop=null
    }

    protected fun requestFeedSyncRead(forceAble : Boolean = false){
        feedItemsViewModel.isSyncAble().isTrue {
            requestFeedSync(
                        context = requireContext(),
                        feedId = feedId,
                        feedTag = feedTag ,
                        ignoreConnectivitySettings = true,
                        parallell = true,
                        force = forceAble,
                        forceNetwork = true
                )

         }
    }

    protected fun requestFeedSyncAll(){
            requestFeedSync(
                    context = requireContext(),
                    parallell = true,
                    ignoreConnectivitySettings = true,
                    forceNetwork = true
            )
    }

    protected fun onSyncBroadcast(syncing: Boolean) {
        if(!syncing) {
            swipeRefreshLayout.refreshComplete()
            if(adapter.itemCount <= 5 || recyclerView.firstVisibleItemPosition <=3)
               currentListReadRefreshCheck()
            else
               feedItemsViewModel.blackSynced = true
        }
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.feed, menu)

        // Don't forget super call here
        super.onCreateOptionsMenu(menu, inflater)

        val searchItem = menu.findItem(R.id.action_search)
        val mSearchView:SearchView = searchItem.actionView as SearchView

        val searchText=feedItemsViewModel.searchText

        if (searchText != null) {
            searchItem.expandActionView()
            mSearchView.post {
                mSearchView.setQuery(searchText, false)
                mSearchView.clearFocus()

            }
        }
        mSearchView.setOnQueryTextFocusChangeListener { v, hasFocus ->
           if (hasFocus) {
               showSearchPop(mSearchView,actionCallback = object:SearchPopCallback{
                   override fun queryByString(queryString: String) {
                       mSearchView.setQuery(queryString, false)
                       searchItems(queryString)
                   }

                   override fun queryByDateTime(firstDay: Date, lastDay: Date) {
                       queryByDate(firstDay, lastDay)
                   }
               })
           }
        }

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                Timber.d("submit text to search:%s",query)
                if(query.isEmpty()) return false

                searchItems(query)

                if(searchHostoryList.contains(query))
                    searchHostoryList.remove(query)

                searchHostoryList.add(0,query)

                if(searchHostoryList.size > 20)
                    searchHostoryList = searchHostoryList.take(20).toMutableList()
                else
                    searchHostoryList = searchHostoryList

                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {
                return false
            }
        })
        searchHostoryList
        mSearchView.setOnCloseListener {
            Timber.d("closed search")
            finishSearch()
            false
        }
    }

    protected fun searchItems(query: String){
        feedItemsViewModel.filterWithSearchText(query)
        refreshCurrentList()
    }

    protected fun finishSearch(){
       feedItemsViewModel.desableSearchModel()
       refreshCurrentList()
    }

    protected fun getTitle():String=(activity as AppCompatActivity?)?.supportActionBar?.title.toString()

    override fun onPrepareOptionsMenu(menu: Menu) {
        val isFeedViewList = feedItemsViewModel.currentModel == ItemListViewModel.FEED && !feedItemsViewModel.isSystemFeed
         menu.findItem(R.id.action_edit_feed)?.isVisible = isFeedViewList
         menu.findItem(R.id.action_delete_feed)?.isVisible = isFeedViewList
         menu.findItem(R.id.action_add_templated)?.isVisible = isFeedViewList
         menu.findItem(R.id.action_share_feed)?.isVisible = isFeedViewList

        menu.findItem(R.id.action_feed_view_tree)?.isVisible = feedItemsViewModel.currentModel == ItemListViewModel.FEED

        menu.findItem(R.id.action_download_history)?.isVisible = feedItemsViewModel.currentModel != ItemListViewModel.DOWNLOADER
        menu.findItem(R.id.action_read_history)?.isVisible = feedItemsViewModel.currentModel != ItemListViewModel.HISTORY

        if(feedId in SYSTEM_FEED_LIST) {
            menu.findItem(R.id.action_sync)?.isVisible = false
        }

        // Set toggleable state
        menu.findItem(R.id.action_only_unread)?.let { menuItem ->
            val onlyUnread = feedItemsViewModel.isOnlyUnread()
            menuItem.isChecked = onlyUnread
            menuItem.setTitle(if (onlyUnread) R.string.show_all_items else R.string.show_unread_items)

            menuItem.setIcon(
                    when (onlyUnread) {
                        true -> R.drawable.ic_visibility_off_white_24dp
                        false -> R.drawable.ic_visibility_white_24dp
                    }
            )
        }

        menu.findItem(R.id.action_notify)?.let { menuItem ->
            setNotifyMenuItemState(menuItem)
        }

        menu.findItem(R.id.action_item_order)?.isVisible = false
        menu.findItem(R.id.action_item_order)?.let { menuItem ->
            val onlyUnread = feedItemsViewModel.isOnlyUnread()
            menuItem.isChecked = onlyUnread
            menuItem.setTitle(if (onlyUnread) R.string.item_list_order_asc else R.string.show_unread_items_desc)

            menuItem.setIcon(
                    when (onlyUnread) {
                        true -> R.drawable.ic_visibility_off_white_24dp
                        false -> R.drawable.ic_visibility_white_24dp
                    }
            )
        }

        menu.findItem(R.id.action_start_server)?.setTitle(if (isRssServerRunning()) R.string.action_stop_server else R.string.action_start_server)

        menu.findItem(R.id.action_share_current_opml_qr)?.isVisible = isRssServerRunning()

        super.onPrepareOptionsMenu(menu)
    }

    protected fun updateNotifyMenuItemState(menuItem: MenuItem,notify:Boolean) {
        menuItem.isChecked = notify
        menuItem.isEnabled = true
        if (notify) {
            menuItem.setIcon(R.drawable.ic_notifications_on_white_24dp)
        } else {
            menuItem.setIcon(R.drawable.ic_notifications_off_white_24dp)
        }
        menuItem.setTitle(if (notify) R.string.dont_notify_for_new_items else R.string.notify_for_new_items)
    }

    protected fun setNotifyMenuItemState(menuItem: MenuItem) {
        val notifyMenuAble= when(feedItemsViewModel.currentModel){
            ItemListViewModel.ALL_FEED,ItemListViewModel.GROUP -> true
            ItemListViewModel.FEED -> !feedItemsViewModel.isSystemFeed
            else -> false
        }
        menuItem.isVisible = notifyMenuAble
        if(notifyMenuAble) {
            menuItem.isEnabled=false
            lifecycleScope.launch(Dispatchers.IO) {
               val notify =
                when (feedItemsViewModel.currentModel) {
                    ItemListViewModel.ALL_FEED -> {
                        feedDao.loadLiveFeedsNotify().asFlow().fold(true) { a, b -> a && b }
                    }
                    ItemListViewModel.GROUP -> {
                        feedDao.loadLiveFeedsNotify(tag = feedTag).asFlow().fold(true) { a, b -> a && b }
                    }
                    ItemListViewModel.FEED -> {
                        feedDao.loadLiveFeed(feedId).notify
                    }
                    else -> {false}
                }
                withContext(Dispatchers.Main) {
                    updateNotifyMenuItemState(menuItem,notify)
                }
            }
        }
    }

    protected fun setNotifications(on: Boolean) {
        // Set as notified so we don't spam
        feedItemsViewModel.markFeedItemAsNotified()
        feedViewModel.markAsNotified(feedId, feedTag, on)
    }

    protected fun markCurrentListAsReadAndSync(pageList:List<PreviewItem>){
        markCurrentListAsRead(pageList)
        requireContext().makeToast(getString(R.string.mark_all_as_read))
        if(feedId !in SYSTEM_FEED_LIST)
            requestFeedSyncRead()
    }


    /**
     * Mark all items as read in the list
     */
    protected fun markCurrentListAsRead(pageList:List<PreviewItem>) {
        if (pageList.isEmpty())
            return
        // Cancel any notifications
        requireContext().let { appContext ->
            Timber.d("mark as read items count:%d", pageList.size)
            val ids=when(feedItemsViewModel.isOnlyUnread()){
                // Can be null in case of placeholder values
                true->pageList.filter { previewItem: PreviewItem? -> previewItem?.id!=null}
                false->pageList.filter { previewItem: PreviewItem? -> previewItem?.unread == true }
            }.map { entry ->
                entry.id
            }
            Timber.d("mark as read items count alter filter :%d", ids.size)
            lifecycleScope.launch {
                ids.forEach { id ->
                    cancelNotification(appContext, id)
                }
            }
            // Then mark as read
            feedItemsViewModel.markCurrentListItemAsRead(ids)
            globalViewModel.checkNavigateItems()
        }
    }

    protected fun currentListFilte(pageList:List<PreviewItem>, unread:Boolean):List<Long>{
       return pageList.filter {previewItem: PreviewItem? -> previewItem?.unread == unread}.map { entry->entry.id }
    }

    fun onOptionsItemSelectedWithFab(id : Int){
        when (id) {
            R.id.action_add -> {
               //startActivityForResult(Intent(context, EditFeedActivity::class.java), EDIT_FEED_CODE)
                startEditFeedActivity()
            }
            R.id.action_unread_state_toggle -> {
                //val onlyUnread =!feedItemsViewModel.isOnlyUnread()
                feedItemsViewModel.toggleOnlyUnread()
                refreshCurrentList()
                /*if(feedItemsViewModel.isSearchModel())
                    feedItemsViewModel.searchText?.let { searchItems(it) }*/
            }
            R.id.action_tag -> {
                showItemTagsPop()
            }
            R.id.action_show_empty_card -> {
                if( emptyView.isVisible && adapter.itemCount == 0)
                    startFeedNavigation()
                else
                   toggleEmptyViewBackground()
            }
        }
    }

    fun startFeedNavigation(){
        /*val i = Intent(activity, FeedNavigationActivity::class.java)
        startActivity(i)*/
        startActivity<FeedNavigationActivity>()
    }

    override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
        val id = menuItem.itemId
        return when {
            id == R.id.action_sync -> {
                // Sync all feeds when menu button pressed
               requestFeedSyncAll()
               true
            }
            id == R.id.action_feature-> {
                lifecycleScope.launch(Dispatchers.IO) {
                    showFeatureSelect(featureList = globalViewModel.feedItemFeatureList()) { featureId, title ->
                        featureId?.let {
                            feedItemsViewModel.filterWithFeature(featureId, title)
                            refreshCurrentList()
                        }
                    }
                }
                true
            }
            id == R.id.action_new_favorite->{
               /* val i = Intent(activity, EditFavoriteActivity::class.java)
                i.putExtra(ARG.FEED_ITEM_ID, ID_UNSET)
                startActivity(i)*/

                startActivity<EditFavoriteActivity>(ARG.FEED_ITEM_ID to ID_UNSET)
                true
            }
            id == R.id.action_read_history->{
                feedItemsViewModel.filterWithReadHistory()
                refreshCurrentList()
                true
            }
            id == R.id.action_download_history->{
                feedItemsViewModel.filterWithDownloadHistory()
                refreshCurrentList()
                true
            }

            id == R.id.action_edit_feed && this.feedId > ID_UNSET -> {
                editFeed(feedId,getTitle(),feedTag)
                true
            }
            id == R.id.action_add_templated && this.feedId > ID_UNSET -> {

                editFeed(feedId,getTitle(),feedTag, temp = true)
                true
            }
            id == R.id.action_mark_read_current_list -> {
                markCurrentListAsRead(adapter.getCurrentItemList())
                true
            }
            id == R.id.action_mark_unread_current_list -> {
                adapter.getCurrentItemList().let { pagedList ->
                    currentListFilte(pagedList,false).let{ids->
                        feedItemsViewModel.markAllAsUnRead(ids)
                    }
                }
                true
            }
            id == R.id.action_delete_current_list -> {
                adapter.getCurrentItemList().let { pagedList ->
                    pagedList.map { entry->entry.id }.let{ ids->
                        feedItemsViewModel.markAllAsDelete(ids)
                    }
                }
                true
            }
            id==R.id.action_mark_favorite_current_list->{
                adapter.getCurrentItemList().let { pagedList ->
                    pagedList.map { entry->entry.id }.let{ ids->
                        feedItemsViewModel.markAllAsFavorite(ids)
                    }
                }
                true
            }
            id == R.id.action_read_all -> {
                feedItemsViewModel.markAllFeedItemAsRead()
                true
            }
            id == R.id.action_mark_unread_all -> {
                feedItemsViewModel.markAllAsUnRead()
                true
            }
            id == R.id.action_delete_all -> {
                feedItemsViewModel.markAllAsDelete()
                true
            }

            id == R.id.action_delete_feed && this.feedId > ID_UNSET -> {

                feedViewModel.deleteFeed(this.feedId)
                 // Remove from shortcuts
                requireContext().removeDynamicShortcutToFeed(feedId)

                // Tell activity to open another fragment
                feedItemsViewModel.filterWithAllFeed()
                true
            }
            id == R.id.action_share_feed&& this.feedId > ID_UNSET -> {
                feedViewModel.loadFeed(feedId).let{
                    generateQRCode(QRScanReturnType.FEED.buildContent(it.url.toString()),it.title+"\nfeed id:"+it.id)
                }
                true
            }
            id == R.id.action_edit_hot_feed -> {
                navigateToFeedHotEditFragment()
                true
            }
            id == R.id.action_only_unread -> {
                feedItemsViewModel.toggleOnlyUnread()
                refreshCurrentList()
                val onlyUnread=feedItemsViewModel.isOnlyUnread()
                menuItem.isChecked = onlyUnread
                if (onlyUnread) {
                    menuItem.setIcon(R.drawable.ic_visibility_off_white_24dp)
                } else {
                    menuItem.setIcon(R.drawable.ic_visibility_white_24dp)
                }
                menuItem.setTitle(if (onlyUnread) R.string.show_unread_items else R.string.show_all_items)
                /*if(feedItemsViewModel.isSearchModel())
                    feedItemsViewModel.searchText?.let { searchItems(it) }*/
                true
            }
            id == R.id.action_notify -> {
                val notify = !menuItem.isChecked
                updateNotifyMenuItemState(menuItem,notify)

                setNotifications(notify)
                true
            }
            id == R.id.action_add_url -> {
                //startActivityForResult(Intent(context, EditFeedActivity::class.java), EDIT_FEED_CODE)
                startEditFeedActivity()
                true
            }
            id == R.id.action_add_sms -> {
               /* XXPermissions.with(this)
                    // 申请单个权限
                    .permission(Permission.READ_SMS)
                    // 申请多个权限
                    //.permission(Permission.Group.CALENDAR)
                    // 设置权限请求拦截器（局部设置）
                    //.interceptor(new PermissionInterceptor())
                    // 设置不触发错误检测机制（局部设置）
                    //.unchecked()
                    .request(object : OnPermissionCallback {
                        override fun onGranted(permissions: MutableList<String>, all: Boolean) {
                           *//* if (!all) {
                                requireContext().makeToast("获取部分权限成功，但部分权限未正常授予")
                                return
                            }*//*
                            XPopup.Builder(context).asInputConfirm("订阅短信号码","","13811111111"){
                                val url=SmsSource.buildUrl(it)
                                lifecycleScope.launch(Dispatchers.IO) {
                                    if (feedDao.isExitsFeed(url)) {
                                        withContext(Dispatchers.Main) {
                                            requireContext().makeToast("订阅已存在")
                                        }
                                    } else {
                                        val feed = Feed(
                                            url = URL(url),
                                            title = it,
                                            tag = requireContext().getString(R.string.feed_type_sms)
                                        )

                                        feedDao.upsert(feed)
                                        withContext(Dispatchers.Main) {
                                            editFeed(feed.id, feed.title, feed.tag, _feed = feed)
                                        }
                                    }
                                }
                            }.show()
                        }

                        override fun onDenied(permissions: MutableList<String>, never: Boolean) {
                            if (never) {
                                requireContext().makeToast("被永久拒绝授权，请手动授予读取短信权限")
                                // 如果是被永久拒绝就跳转到应用权限系统设置页面
                                XXPermissions.startPermissionActivity(context, permissions)
                            } else {
                                requireContext().makeToast("获取短信权限失败")
                            }
                        }
                    })*/
                requestPermission(Permission.READ_SMS){
                    onGranted={
                        XPopup.Builder(context).asInputConfirm("订阅短信号码","","13811111111"){
                            val url=SmsSource.buildUrl(it)
                            lifecycleScope.launch(Dispatchers.IO) {
                                if (feedDao.isExitsFeed(url)) {
                                    withContext(Dispatchers.Main) {
                                        requireContext().makeToast("订阅已存在")
                                    }
                                } else {
                                    val feed = Feed(
                                        url = URL(url),
                                        title = it,
                                        tag = requireContext().getString(R.string.feed_type_sms)
                                    )

                                    feedDao.upsert(feed)
                                    withContext(Dispatchers.Main) {
                                        editFeed(feed.id, feed.title, feed.tag, _feed = feed)
                                    }
                                }
                            }
                        }.show()
                    }
                    onDenied={
                        /*if (never) {
                            requireContext().makeToast("被永久拒绝授权，请手动授予读取短信权限")
                            // 如果是被永久拒绝就跳转到应用权限系统设置页面
                            XXPermissions.startPermissionActivity(context, permissions)
                        } else {
                            requireContext().makeToast("获取短信权限失败")
                        }*/
                        requireContext().makeToast("获取短信权限失败")
                    }
                    onShowRequestRationale={
                        requireContext().makeToast("获取短信权限失败.onShowRequestRationale")
                    }
                }
                true
            }
            id == R.id.action_add_email -> {

                XPopup.Builder(context).asInputConfirm("订阅邮件发件人名称","","百度科技"){
                    val url=EmailSource_K9.buildUrl(it)
                    lifecycleScope.launch(Dispatchers.IO) {
                        if (feedDao.isExitsFeed(url)) {
                            withContext(Dispatchers.Main) {
                                requireContext().makeToast("订阅已存在")
                            }
                        } else {
                            val feed = Feed(
                                url = URL(url),
                                title = it,
                                tag = requireContext().getString(R.string.feed_type_email)
                            )

                            feedDao.upsert(feed)
                            withContext(Dispatchers.Main) {
                                editFeed(feed.id, feed.title, feed.tag, _feed = feed)
                            }
                        }
                    }
                }.show()

                /*val k9Readable=ContextCompat.checkSelfPermission(requireContext(),EmailSource_K9.EMAIL_K9_Permission_READ)==PackageManager.PERMISSION_GRANTED
                Timber.d("k9 email read able:$k9Readable")


                XXPermissions.with(this)
                    // 申请单个权限
                    .permission(EmailSource_K9.EMAIL_K9_Permission_READ)
                    // 申请多个权限
                    //.permission(Permission.Group.CALENDAR)
                    // 设置权限请求拦截器（局部设置）
                    //.interceptor(new PermissionInterceptor())
                    // 设置不触发错误检测机制（局部设置）
                    .unchecked()
                    .request(object : OnPermissionCallback {
                        override fun onGranted(permissions: MutableList<String>, all: Boolean) {
                            *//** if (!all) {
                                 requireContext().makeToast("获取部分权限成功，但部分权限未正常授予")
                                 return
                             }**//*
                            XPopup.Builder(context).asInputConfirm("订阅邮件号码","","sample@mail.com"){
                                val url=EmailSource_K9.buildUrl(it)
                                lifecycleScope.launch(Dispatchers.IO) {
                                    if (feedDao.isExitsFeed(url)) {
                                        withContext(Dispatchers.Main) {
                                            requireContext().makeToast("订阅已存在")
                                        }
                                    } else {
                                        val feed = Feed(
                                            url = URL(url),
                                            title = it,
                                            tag = requireContext().getString(R.string.feed_type_email)
                                        )

                                        feedDao.upsert(feed)
                                        withContext(Dispatchers.Main) {
                                            editFeed(feed.id, feed.title, feed.tag, _feed = feed)
                                        }
                                    }
                                }
                            }.show()
                        }

                        override fun onDenied(permissions: MutableList<String>, never: Boolean) {
                            if (never) {
                                requireContext().makeToast("被永久拒绝授权，请手动授予读取邮件权限")
                                // 如果是被永久拒绝就跳转到应用权限系统设置页面
                                XXPermissions.startPermissionActivity(context, permissions)
                            } else {
                                requireContext().makeToast("获取邮件权限失败")
                            }
                        }
                    })*/
                true
            }
            id == R.id.action_add_dir ->{
                //requestReadDir.launch(null)
                //FileManager.isStoragePermissionGranted(requireActivity())
                folderPicker(""){
                    Timber.d(" read dir:$it")

                    it?:return@folderPicker

                    lifecycleScope.launch(Dispatchers.IO) {

                        val url=DirSource.buildUrl(it.toString().htmlEncode())

                        if (feedDao.isExitsFeed(url)) {
                            withContext(Dispatchers.Main) {
                                requireContext().makeToast("订阅已存在")
                            }
                        } else {
                            val feed = Feed(
                                url = URL(url),
                                title = it.path.toString(),
                                tag = requireContext().getString(R.string.feed_type_dir)
                            )

                            feedDao.upsert(feed)

                            withContext(Dispatchers.Main) {
                                editFeed(feed.id, feed.title, feed.tag, _feed = feed)
                            }
                        }
                    }
                }
                true
            }
            id == R.id.action_feed_rule -> {
                //startActivity(Intent(activity, FeedRuleListActivity::class.java))
                startActivity<FeedRuleListActivity>()
                true
            }
            id == R.id.action_opml_export -> {
                // Choose file, then export
               /* val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
                intent.type = "text/opml"
                intent.putExtra(Intent.EXTRA_TITLE, "feeder.opml")
                startActivityForResult(intent, EXPORT_OPML_CODE)*/

                createFile("feeder.opml","text/opml"){
                    it?.let {
                        lifecycleScope.launch(Dispatchers.Default) {
                            exportOpml(requireContext(), it)
                        }
                    }
                }
                true
            }
            id == R.id.action_opml_import -> {
                // Choose file
//                val intent= Intent(Intent.ACTION_OPEN_DOCUMENT)
//                intent.addCategory(Intent.CATEGORY_OPENABLE)
//                intent.type = "*/*"
//                intent.putExtra(Intent.EXTRA_MIME_TYPES,
//                        arrayOf("text/plain", "text/xml", "text/opml", "*/*"))
//                startActivityForResult(intent, IMPORT_OPML_CODE)

                filePicker("feeder.opml", arrayOf("text/plain", "text/xml", "text/opml", "*/*")){
                    it?.let{
                        lifecycleScope.launch(Dispatchers.Default) {
                            importOpml(requireContext(), it)
                        }
                    }
                }
                true
            }
            id == R.id.action_share_current_opml_qr ->{
                generateQRCode( QRScanReturnType.OPML.buildContent(RssServer.getOpmlExportAddr(requireContext())),getString(R.string.share_current_opml_qr))
                true
            }
            id == R.id.action_settings -> {
                navigateToSettingFragment()
                true
            }
            id == R.id.action_reportbug -> {
                try {
                    startActivity(openGitlabIssues(context))
                } catch (e: ActivityNotFoundException) {
                    requireContext().makeToast(getString(R.string.no_email_client))
                }
                true
            }
            id == R.id.action_start_server-> {
                if(isRssServerRunning()){
                    stop(requireActivity())
                    requireContext().makeToast("to stop rssServer..")
                }else{
                    start(requireActivity())
                    requireContext().makeToast("to start rssServer IP:${context?.getIp()}:8080/feed")
                }
                true
            }
            id==R.id.action_feed_view_mini->{
                feedItemsViewModel.changeFeedViewListType(FeedViewListType.MINI)
                return true
            }
            id==R.id.action_feed_view_normal->{
                feedItemsViewModel.changeFeedViewListType(FeedViewListType.NORMAL)
                return true
            }
            id==R.id.action_feed_view_picture->{
                feedItemsViewModel.changeFeedViewListType(FeedViewListType.PICTURE)
                return true
            }
            id==R.id.action_feed_view_tree->{
                val treeItemMap = FeedItemCategoryHelper.saveTagValueMap.toList()
                XPopup.Builder(context).asCenterList("选择目录树", treeItemMap.map { it.second }.toTypedArray()
                ) { position, _ ->
                    val treeId= treeItemMap[position].first
                    feedItemsViewModel.setFeedViewListTypeTreeName(this.feedId,treeId)
                    feedItemsViewModel.changeFeedViewListType(FeedViewListType.TREE)
                }.show()
                return true
            }
            id==R.id.action_navigation_feed->{
                startFeedNavigation()
                return true
            }
            id==R.id.action_check_update->{
                checkUpdate()
                return true
            }
            id==R.id.action_item_order->{
                val listOrder = !menuItem.isChecked
                globalViewModel.changeListItemOrder(listOrder)
                menuItem.isChecked = listOrder
                if (listOrder) {
                    menuItem.setIcon(R.drawable.ic_visibility_off_white_24dp)
                } else {
                    menuItem.setIcon(R.drawable.ic_visibility_white_24dp)
                }
                menuItem.setTitle(if (listOrder) R.string.item_list_order_asc else R.string.show_unread_items_desc)
                true
            }
            id==R.id.action_tag->{
                showItemTagsPop()
                true
            }
            id == R.id.action_new_favorite_scan_qr-> {
                //decodePermission(CAMERA_REQ_CODE)
                startScanKit()
                true
            }

            else -> super.onOptionsItemSelected(menuItem)
        }
    }


    fun editFeed(feedId: Long,title:String,feedTag:String,temp:Boolean=false,_feed:Feed?=null){
        val i = Intent(activity, EditFeedActivity::class.java)
        // TODO do not animate the back movement here
        i.putExtra(ARG.FEED_ID, feedId)
        if(temp)
            i.putExtra(ARG.TEMPLATE, true)
        else
            i.putExtra(ARG.TITLE, title)
        i.putExtra(ARG.TAG, feedTag)
        val feed= _feed ?: feedViewModel.loadFeed(feedId)

        i.putExtra(ARG.CUSTOM_TITLE, feed.customTitle)
        i.putExtra(ARG.FEED_SYNC, feed.syncAble)
        i.putExtra(ARG.FEED_SYNC_PERIOD, feed.sync_period)
        i.data = Uri.parse(feed.url.toString())

        startActivity(i)
    }

    fun queryByDate(firstDay: Date, lastDay: Date) {
        Timber.d("query by date start:${DateUtils.toString(firstDay)} - end:${DateUtils.toString(lastDay)}")
        feedItemsViewModel.filterByDate(firstDay, lastDay)
        refreshCurrentList()
    }

    fun showSearchPop(view:View,actionCallback:SearchPopCallback){
      XPopup.Builder(context)
          .atView(view)
          .isDarkTheme(PrefUtils.isNightMode(requireContext()))
          .isViewMode(true)
          .hasShadowBg(false)
          .maxWidth((ScreenUtils.getScreenWidth(requireContext())*0.7).toInt())
          //.maxHeight((ScreenUtils.getScreenHeight(requireContext())*0.7).toInt())
          .asCustom(
            FeedItemSearchPopup(context =requireContext(), actionCallback)
        ).show()
    }

    fun showItemTagsPop(){
        XPopup.Builder(context)
            .maxHeight((ScreenUtils.getScreenHeight(requireContext())*0.7).toInt())
            .asCustom(
                ItemTagsFilterDrawerPopup(
             context=requireContext(),
             itemTagClickCallBack = object:ItemTagClickCallBackAdapter(itemTagClickCallBack){
                override fun selectedTagsToFilter(tags: List<String>) {
                     if(tags.isNotEmpty())
                         feedItemsViewModel.filterWithTags(tags)
                     else
                         feedItemsViewModel.desableSearchModel()
                    refreshCurrentList()
                 }
             },
             repository = feedItemTagRepository
        )
        ).show()
    }

    open fun checkUpdate(){
        try {
            AppUpdaterUtils(activity)
                    .setUpdateFrom(UpdateFrom.XML)
                    .setUpdateXML(getUpdateXmlUrl())
                    .withListener(object : AppUpdaterUtils.UpdateListener {
                        override fun onSuccess(update: Update?, isUpdateAvailable: Boolean?) {
                            Timber.d("come in checkUpdate onSuccess isUpdateAvilable:$isUpdateAvailable \tupdate:$update...")
                            context?.let {
                                if (isUpdateAvailable != null && isUpdateAvailable == true && update != null) {
                                    Timber.d("come in checkUpdate onSuccess Avilable...")
                                    showUpdateAvailableDialog(it,
                                            title = getString(R.string.message_update_avilable),
                                            content = getString(R.string.message_update_content) + "\n" + update?.releaseNotes,
                                            btnPositive = getString(R.string.update),
                                            btnNegative = getString(R.string.update_late),
                                            updateClickListener = { dialog, which -> openLinkInBrowser(context!!, update.urlToDownload.toString()) },
                                            dismissClickListener = { dialog, which -> dialog.dismiss() })?.show()
                                } else {
                                    showUpdateNotAvailableDialog(it, title = getString(R.string.message_no_update_avilable), content = getString(R.string.message_no_update_content))?.show()
                                }
                            }
                        }

                        override fun onFailed(error: AppUpdaterError?) {
                            context?.makeToast("check failed..")
                        }

                    }).start()
        }catch (e:Exception){
            context?.makeToast("check failed..")
        }
    }

    open fun getUpdateXmlUrl():String="https://raw.githubusercontent.com/wushunlian/app/master/feeder/update-changelog.xml"

    fun startScanKit(){
        requestMultiplePermission(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE){
              onAllGranted = {
                  startActivity<ScanKitActivity>("ScanFormatValue" to HmsScan.QRCODE_SCAN_TYPE){data->
                      val obj: HmsScan? = data?.getParcelableExtra(ScanUtil.RESULT)
                      obj?.let{
                          val scanString=obj.getOriginalValue()
                          when(val scanType=QRScanUtils.getQRScanType(scanString)){
                              QRScanReturnType.FEED->{
                                  val intent = Intent(activity, EditFeedActivity::class.java)
                                  intent.putExtra(Intent.EXTRA_TEXT, scanType.getContent(scanString))
                                  startActivity(intent)
                              }
                              //QRScanReturnType.ITEM->{}
                              QRScanReturnType.OPML->{
                                  startFeedNavigation(requireContext(),scanType.getContent(scanString))
                              }
                              else-> {
                                  if(QRScanUtils.isOpml(scanString)) {
                                      startFeedNavigation(requireContext(), scanString)
                                  } else {
                                      val intent = Intent(activity, EditFavoriteActivity::class.java)
                                      intent.putExtra(Intent.EXTRA_TEXT, scanString)
                                      startActivity(intent)
                                  }
                              }
                          }
                      }
                  }
              }
            onDenied={
                requireContext().toastError("scan request permission ${it.toString()} fails")
            }
        }

       /* requestMultiplePermission(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE,
            onAllGranted = {
                startActivity<ScanKitActivity>("ScanFormatValue" to HmsScan.QRCODE_SCAN_TYPE){data->
                    val obj: HmsScan? = data?.getParcelableExtra(ScanUtil.RESULT)
                    obj?.let{
                        val scanString=obj.getOriginalValue()
                        when(val scanType=QRScanUtils.getQRScanType(scanString)){
                            QRScanReturnType.FEED->{
                                val intent = Intent(activity, EditFeedActivity::class.java)
                                intent.putExtra(Intent.EXTRA_TEXT, scanType.getContent(scanString))
                                startActivity(intent)
                            }
                            //QRScanReturnType.ITEM->{}
                            QRScanReturnType.OPML->{
                                startFeedNavigation(requireContext(),scanType.getContent(scanString))
                            }
                            else-> {
                                if(QRScanUtils.isOpml(scanString)) {
                                    startFeedNavigation(requireContext(), scanString)
                                } else {
                                    val intent = Intent(activity, EditFavoriteActivity::class.java)
                                    intent.putExtra(Intent.EXTRA_TEXT, scanString)
                                    startActivity(intent)
                                }
                            }
                        }
                    }
                }
            },
            onDenied = {

            },
            onShowRequestRationale = {

            }
            )*/
    }

    val CAMERA_REQ_CODE = 1111
    val REQUEST_CODE_SCAN_ONE = 0X01;
    /**
     * Apply for permissions.
     */
    private  fun decodePermission(requestCode: Int) {
       requestPermissions(arrayOf(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE),requestCode)
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        if (permissions == null || grantResults == null) {
            return;
        }
        //Default View Mode
        if (requestCode === CAMERA_REQ_CODE) {
            val intent = Intent(context, ScanKitActivity::class.java)
            intent.putExtra("ScanFormatValue",HmsScan.QRCODE_SCAN_TYPE)
            this.startActivityForResult(intent, REQUEST_CODE_SCAN_ONE)
        }
    }

    fun startEditFeedActivity(){
        startActivity<EditFeedActivity>(){
            it?.data?.lastPathSegment?.toLong()?.let { id ->
                navigateToFeedFragment(id,it.extras?.getString(ARG.TAG))
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (resultCode != Activity.RESULT_OK) {
            return
        }
        when (requestCode) {
            EXPORT_OPML_CODE -> {
                val uri: Uri? = data?.data
                if (uri != null) {
                    val appContext = requireContext().applicationContext
                    lifecycleScope.launch(Dispatchers.Default) {
                        exportOpml(appContext, uri)
                    }
                }
            }
            IMPORT_OPML_CODE -> {
                val uri: Uri? = data?.data
                if (uri != null) {
                    val appContext = requireContext().applicationContext
                    lifecycleScope.launch(Dispatchers.Default) {
                        importOpml(appContext, uri)
                    }
                }
            }
            EDIT_FEED_CODE -> {
                data?.data?.lastPathSegment?.toLong()?.let { id ->
                    navigateToFeedFragment(id,data.extras?.getString(ARG.TAG))
                }
            }
            REQUEST_CODE_SCAN_ONE -> {
                val obj: HmsScan? = data?.getParcelableExtra(ScanUtil.RESULT)
                obj?.let{
                    val scanString=obj.getOriginalValue()
                    when(val scanType=QRScanUtils.getQRScanType(scanString)){
                        QRScanReturnType.FEED->{
                            val intent = Intent(activity, EditFeedActivity::class.java)
                            intent.putExtra(Intent.EXTRA_TEXT, scanType.getContent(scanString))
                            startActivity(intent)
                        }
                        //QRScanReturnType.ITEM->{}
                        QRScanReturnType.OPML->{
                             startFeedNavigation(requireContext(),scanType.getContent(scanString))
                        }
                        else-> {
                            if(QRScanUtils.isOpml(scanString)) {
                                startFeedNavigation(requireContext(), scanString)
                            } else {
                                val intent = Intent(activity, EditFavoriteActivity::class.java)
                                intent.putExtra(Intent.EXTRA_TEXT, scanString)
                                startActivity(intent)
                            }
                        }
                    }
                }
            }
        }
    }

    abstract fun navigateToFeedFragment(id:Long,tag:String?)

    abstract fun navigateToSettingFragment()

    abstract fun navigateToFeedHotEditFragment()

    abstract fun navigateToReaderFragment()

    abstract fun navigateToReaderWebViewFragment(link:String?,enclosureLink:String?)

    abstract fun navigateToFeedRuleFragment(feedId: Long?=0, regContent: String?=null, adFlag: Boolean?=null)


    companion object{
        var searchHostoryList by StateSavedVar(MMKVStoreServer.get(), "Popup.search.hostory_list", mutableListOf<String>())
    }
}



class FeatureSelectCenterPopup(context: Context, private val featureList: List<FeedItemFeature>, private val selectIndex:Int=-1, private val listener:FeatureCallBack):CenterPopupView(context){
    override fun getImplLayoutId(): Int {
        return R.layout.popup_feature
    }
    override fun onCreate() {
        super.onCreate()
        val featureRecyclerView=findViewById<RecyclerView>(R.id.feature_recyclerView)
        val adapter=FeatureAdapter(selectIndex,listener)
        findViewById<ImageView>(R.id.feature_add_imageView).setOnClickListener {
            XPopup.Builder(context).asInputConfirm(context.getString(R.string.feature_add),"") { text ->
                text.isNotEmpty().isTrue {
                            val featureItem= FeedItemFeature(title = text)
                            listener.featureAdd(featureItem).let{
                                adapter.addItem(featureItem)
                            }
                }
            }.show()
        }
        featureRecyclerView.layoutManager=LinearLayoutManager(context)
        featureRecyclerView.adapter=adapter
        adapter.submitList(featureList.toMutableList())
    }

    class FeatureAdapter(var selectIndex: Int,val featureCallback:FeatureCallBack) : ListAdapter<FeedItemFeature, FeatureHoder>(FeatureDiffCallback()){

       private lateinit var mutableList:MutableList<FeedItemFeature>

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeatureHoder {
            return FeatureHoder(LayoutInflater.from(parent.context).inflate(R.layout.list_feature, parent, false))
        }

        override fun onBindViewHolder(holder: FeatureHoder, position: Int) {
           val item=getItem(position)
           holder.featureDel.visibility=View.VISIBLE
           holder.featureEdit.visibility=View.VISIBLE
           holder.featureSelected.visibility=when(position==selectIndex){true->View.VISIBLE false->View.INVISIBLE}
           holder.featureDel.visibility=when(position==selectIndex){true->View.INVISIBLE false->View.VISIBLE}
           holder.featureDel.setOnClickListener {
               featureCallback.featureDel(item)
               mutableList.remove(item)
               this.notifyItemRemoved(position)
           }
           holder.featureEdit.setOnClickListener {
               featureCallback.featureEdit(item){_->
                   this.notifyItemChanged(position)
               }
           }
           holder.featureTitle.setOnClickListener { featureCallback.featureSelect(item) }
           holder.featureTitle.text= item.title
            (item.id== ID_UNSET).isTrue {
                holder.featureDel.visibility=View.INVISIBLE
                holder.featureEdit.visibility=View.INVISIBLE
            }
        }

        override fun submitList(list: MutableList<FeedItemFeature>?) {
            this.mutableList=list?: mutableListOf()
        }

        override fun getItem(position: Int): FeedItemFeature {
            return mutableList[position]
        }

        override fun getItemCount(): Int {
            return mutableList.size
        }

        override fun getItemId(position: Int): Long {
            return getItem(position).id
        }

        override fun getCurrentList(): MutableList<FeedItemFeature> {
            return mutableList
        }

        fun addItem(item: FeedItemFeature){
            mutableList.add(item)
            this.notifyItemInserted(mutableList.size)
        }
    }

    class FeatureDiffCallback: ItemCallback<FeedItemFeature>(){
        override fun areItemsTheSame(oldItem: FeedItemFeature, newItem: FeedItemFeature): Boolean {
            return oldItem.id==newItem.id
        }

        override fun areContentsTheSame(oldItem: FeedItemFeature, newItem: FeedItemFeature): Boolean {
            return oldItem.id==newItem.id&&oldItem.title==newItem.title
        }
    }

    class FeatureHoder(v: View):RecyclerView.ViewHolder(v){
          val featureEdit: ImageView =v.findViewById(R.id.feature_edit_imageView)
          val featureDel: ImageView =v.findViewById(R.id.feature_del_imageView)
          val featureTitle: TextView =v.findViewById(R.id.feature_title)
          val featureSelected:ImageView=v.findViewById(R.id.imageView_Selected)
    }
}


interface FeatureCallBack{
     fun featureSelect(featureId: FeedItemFeature)
     fun featureEdit(featureId: FeedItemFeature, editCallBack: (String)->Unit)
     fun featureDel(featureId: FeedItemFeature)
     fun featureAdd(featureId: FeedItemFeature)
}

fun showUpdateAvailableDialog(context: Context, title: String?, content: String?, btnNegative: String?, btnPositive: String?, updateClickListener: DialogInterface.OnClickListener?, dismissClickListener: DialogInterface.OnClickListener?): AlertDialog? {
    return AlertDialog.Builder(context)
            .setTitle(title)
            .setMessage(content)
            .setPositiveButton(btnPositive, updateClickListener)
            .setNegativeButton(btnNegative, dismissClickListener)
            .setCancelable(true)
            .create()
}

fun showUpdateNotAvailableDialog(context: Context, title: String?, content: String?): AlertDialog? {
    return AlertDialog.Builder(context)
            .setTitle(title)
            .setMessage(content)
            .setPositiveButton(context.resources.getString(android.R.string.ok)) { dialogInterface, i ->dialogInterface.dismiss() }
            .setCancelable(true)
            .create()
}

class FeedItemSearchPopup(context: Context, private val actionCallback:SearchPopCallback):AttachPopupView(context){

    val calendarArray= listOf(R.string.calendar_option_hour,
        R.string.calendar_option_day,
        R.string.calendar_option_3day,
        R.string.calendar_option_week,
        R.string.calendar_option_3week,
        R.string.calendar_option_month
    )

    override fun getImplLayoutId(): Int {
        return R.layout.popup_search
    }


    fun clearTime(date:Calendar){
        date.set(Calendar.HOUR_OF_DAY,0)
        date.set(Calendar.MINUTE,0)
        date.set(Calendar.SECOND,0)
    }

    fun coventToDate(calendar:com.haibin.calendarview.Calendar,onlyDay:Boolean=false):Calendar{
        val sameDate = Calendar.getInstance()
        if(onlyDay)
           sameDate.set(calendar.year,calendar.month-1,calendar.day,0,0,0)
        else
            sameDate.set(calendar.year,calendar.month-1,calendar.day,0,0,0)
        return sameDate
    }

    @OptIn(InternalCoroutinesApi::class)
    override fun onCreate() {
        super.onCreate()
        val calendarLayout=findViewById<CalendarLayout>(R.id.calendarViewLayout)
        val calendarView=findViewById<CalendarView>(R.id.calendarView)
        val calendarSelect=findViewById<StackLabel>(R.id.calendar_tool)

        calendarArray.forEach {
            calendarSelect.addLabel(context.getString(it))
        }

        calendarSelect.setOnLabelClickListener { index, v, s ->
           val startDate=Calendar.getInstance()
           val endDate=Calendar.getInstance()
            when(calendarArray[index]){
                R.string.calendar_option_hour->{
                    startDate.add(Calendar.HOUR_OF_DAY,-1)
                }
                R.string.calendar_option_day->{
                    clearTime(startDate)
                    calendarView.scrollToCurrent()
                }
                R.string.calendar_option_3day->{
                    clearTime(startDate)
                    startDate.add(Calendar.DAY_OF_MONTH,-2)
                }
                R.string.calendar_option_week->{
                    clearTime(startDate)
                    startDate.add(Calendar.WEEK_OF_MONTH,-1)
                }
                R.string.calendar_option_3week->{
                    clearTime(startDate)
                    startDate.add(Calendar.WEEK_OF_MONTH,-3)
                }
                R.string.calendar_option_month->{
                    clearTime(startDate)
                    startDate.add(Calendar.MONTH,-1)
                }
            }
            actionCallback.queryByDateTime(startDate.time, endDate.time)
        }
        val hot=findViewById<StackLabel>(R.id.stackLabelView_hots_search)
        hot.addLabel("手机")
        hot.setOnLabelClickListener { index, v, s ->
            actionCallback.queryByString(s)
        }

        val host=findViewById<StackLabel>(R.id.stackLabelView_hosty_search)

        AbstractFeedFragment.searchHostoryList.forEach {
            host.addLabel(it)
            host.setOnLabelClickListener { index, v, s ->
                actionCallback.queryByString(s)
            }
        }

        calendarView.setOnCalendarSelectListener(object:CalendarView.OnCalendarSelectListener{
            override fun onCalendarOutOfRange(calendar: com.haibin.calendarview.Calendar?) {
            }

            override fun onCalendarSelect(
                calendar: com.haibin.calendarview.Calendar?,
                isClick: Boolean
            ) {
                if(isClick)
                    calendar?.let {
                        val startDate = coventToDate(it).time
                        val endDate = coventToDate(it).apply {
                            add(Calendar.DAY_OF_MONTH,1)
                        }.time
                        actionCallback.queryByDateTime(startDate, endDate)
                }
            }
        })
        calendarView.setOnCalendarRangeSelectListener(object:CalendarView.OnCalendarRangeSelectListener{
            override fun onCalendarSelectOutOfRange(calendar: com.haibin.calendarview.Calendar?) {
            }

            override fun onSelectOutOfRange(
                calendar: com.haibin.calendarview.Calendar?,
                isOutOfMinRange: Boolean
            ) {
            }

            var startDate:com.haibin.calendarview.Calendar?=null
            var endDate:com.haibin.calendarview.Calendar?=null

            override fun onCalendarRangeSelect(
                calendar: com.haibin.calendarview.Calendar?,
                isEnd: Boolean
            ) {
                calendar?.let {
                    if(isEnd) endDate=it else startDate=it
                    if(startDate!=null&&endDate!=null) {
                        actionCallback.queryByDateTime(coventToDate(startDate!!).time, coventToDate(endDate!!).time)
                    }
                }
            }
        })
    }
}

interface SearchPopCallback{

    fun queryByString(queryString: String)

    fun queryByDateTime(firstDay:Date,lastDay:Date)
}


class SampleFeedItemSelectCenterPopup(context: Context, private val itemList: Flow<List<PreviewItem>>, private val selectIndex:Int=-1, private val itemDao: FeedItemDao, private val actionCallback: ActionCallback):CenterPopupView(context){
    override fun getImplLayoutId(): Int {
        return R.layout.popup_feature
    }
    override fun onCreate() {
        super.onCreate()
        val featureRecyclerView = findViewById<RecyclerView>(R.id.feature_recyclerView)
        val adapter =FeedItemListAdapter(context,itemDao, true, actionCallback)

        findViewById<ImageView>(R.id.feature_add_imageView).setOnClickListener {
            /*XPopup.Builder(context)
                .asInputConfirm(context.getString(R.string.feature_add), "") { text ->
                    text.isNotEmpty().isTrue {
                        val featureItem = FeedItemFeature(title = text)
                        listener.featureAdd(featureItem).let {
                            adapter.addItem(featureItem)
                        }
                    }
                }.show()*/
        }
        featureRecyclerView.layoutManager = LinearLayoutManager(context)
        featureRecyclerView.adapter = adapter

        actionCallback.coroutineScope().launch {
            itemList.collect {
                withContext(Dispatchers.Main) {
                    adapter.submitList(it)
                }
            }
        }
    }
}